#include <Arduino.h>
#include "driver/rgb_led.h"
#include "driver/dev_imu.h"
#include <arduinoFFT.h>

#define ADC1 35//ADC引脚

Pixel rgb;

uint8_t rgb_buf[RGB_LED_NUM*3];

#if 0
int column_rgb[8][3] = {
  {255,   0, 120},
  {255,   0, 200},
  {234,   0, 255},
  {174,   0, 255},
  {120,   0, 255},
  { 60,   0, 255},
  {  0,  30, 255},
  {  0, 140, 255}
};
#else
int column_rgb[12][3] = {
  {255, 128,   0},
  {255, 255,   0},
  {128, 255,   0},
  {  0, 255,   0},
  {  0, 255, 128},
  // {  0, 255, 255},
  {  0, 128, 255},
  // {  0,   0, 255},
  {128,   0, 255},
  // {255,   0, 255},
  {255,   0, 128},
  // {255,   0,   0},
};

// int column_rgb[12][3] = {
//   {255,   0, 255},
//   {224,   0, 255},
//   {192,   0, 255},
//   {160,   0, 255},
//   {128,   0, 255},
//   { 96,   0, 255},
//   { 64,   0, 255},
//   { 32,   0, 255},
//   {  0,   0, 255},
//   {  0,  32, 255},
//   {  0,  64, 255},
//   {  0,  96, 255}
// };
#endif

/***********************************************************/
/*                           FFT                           */
/***********************************************************/
#define SAMPLES 128            //Must be a power of 2

double vReal[SAMPLES];  // 实部
double vImag[SAMPLES];  // 虚部

const double samplingFrequency = 20000;  // 采样频率(adc的实际采样率)
double xHz = 0;

arduinoFFT FFT = arduinoFFT();

/***********************************************************/
/*                                                         */
/***********************************************************/
void rgb_top_update(uint8_t x, uint8_t y, int r, int g, int b);
void screenUpdate(uint8_t mode);

void setup() {
  // put your setup code here, to run once:

  Serial.begin(115200);

  rgb.init();
  rgb.setBrightness(0.2);
  memset(rgb_buf, 0, sizeof(rgb_buf));

  /* 陀螺仪初始化 */
  // mpu.init();

  pinMode(ADC1, ANALOG);

  adcAttachPin(ADC1);       // 将引脚连接到ADC
  analogReadResolution(16); //设置aliogRead返回值的分辨率
}

void loop() {
  // put your main code here, to run repeatedly:

  double adc_max = 0;
  double adc_min = 100000;

  for (int i = 0; i < SAMPLES; i++)
  {
    vReal[i] = analogRead(ADC1);
    vImag[i] = 0;
    if (vReal[i] > adc_max)
    {
      adc_max = vReal[i];
    }
    if (vReal[i] < adc_min)
    {
      adc_min = vReal[i];
    }
  }
  Serial.println(adc_max - adc_min);

  /* 幅度太小的认为是噪声，滤除 */ 
  if (adc_max - adc_min < 150)
  {
    for (int i = 0; i < SAMPLES; i++)
    {
      vReal[i] = 0;
    }
  }

  // ++ FFT
  FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
  FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
  xHz = FFT.MajorPeak(vReal, SAMPLES, samplingFrequency);
  // -- FFT

  screenUpdate(0);
  // mpu.update(100);
}


/* rgb更新 */
void screenUpdate(uint8_t mode)
{
  static uint32_t nextTimeAt = 0;

  if (millis() < nextTimeAt) return;
  nextTimeAt = millis() + 50;

  /* 计算显示的值 */
  uint8_t y_num = 0;
  double vReal_max = 0;
  uint16_t vReal_gain = 0;
  static uint32_t vReal_max0_cnt = 0;
  static uint8_t test_cnt = 0;
  uint8_t single_color = 255;

  test_cnt = (test_cnt + 1) % 8;

  for (uint8_t x = 2; x < SAMPLES; x++)
  {
    if (vReal[x] > vReal_max)
    {
      vReal_max = vReal[x];
    }
  }

  vReal_gain = vReal_max * 0.14 + 10;

  switch (mode)
  {
    // 柱形彩色,顶部白色
    case 0:
      for (uint8_t x = 0; x < RGB_LED_NUM_X; x++)
      {
        y_num = (uint8_t)(vReal[x+2] / vReal_gain);
        if (y_num > 7) y_num = 7;

        // 显示柱形图区域
        for (uint8_t i = 0; i <= RGB_LED_NUM_Y; i++)
        {
          if (i < y_num)
          {
            rgb.setRGB(x, i, column_rgb[x][0], column_rgb[x][1], column_rgb[x][2]);  // 点亮
          }
          else
          {
            rgb.setRGB(x, i, 0, 0, 0);    // 熄灭
          }
        }

        // 更新顶部像素
        rgb_top_update(x, y_num, 255, 255, 255);
      }
      break;

    // 柱形彩色（滚动）,顶部白色
    case 1:
      for (uint8_t x = 0; x < RGB_LED_NUM_X; x++)
      {
        y_num = (uint8_t)(vReal[x+2] / vReal_gain);
        if (y_num > 7) y_num = 7;

        // 显示柱形图区域
        for (uint8_t i = 0; i <= RGB_LED_NUM_Y; i++)
        {
          if (i < y_num)
          {
            rgb.setRGB(x, i, column_rgb[(test_cnt+x)%8][0], column_rgb[(test_cnt+x)%8][1], column_rgb[(test_cnt+x)%8][2]);  // 点亮
          }
          else
          {
            rgb.setRGB(x, i, 0, 0, 0);    // 熄灭
          }
        }

        // 更新顶部像素
        rgb_top_update(x, y_num, 255, 255, 255);
      }
      break;

    // 柱形白色,顶部彩色
    case 2:
      for (uint8_t x = 0; x < RGB_LED_NUM_X; x++)
      {
        y_num = (uint8_t)(vReal[x+2] / vReal_gain);
        if (y_num > 7) y_num = 7;

        // 显示柱形图区域
        for (uint8_t i = 0; i <= RGB_LED_NUM_Y; i++)
        {
          if (i < y_num)
          {
            rgb.setRGB(x, i, 255, 255, 255);  // 点亮
          }
          else
          {
            rgb.setRGB(x, i, 0, 0, 0);    // 熄灭
          }
        }

        // 更新顶部像素
        rgb_top_update(x, y_num, column_rgb[x][0], column_rgb[x][1], column_rgb[x][2]);
      }
      break;

    case 3: if (single_color == 255) single_color = 0;
    case 4: if (single_color == 255) single_color = 3;
    case 5: if (single_color == 255) single_color = 5;
    case 6: if (single_color == 255) single_color = 7;
      for (uint8_t x = 0; x < RGB_LED_NUM_X; x++)
      {
        y_num = (uint8_t)(vReal[x+2] / vReal_gain);
        if (y_num > 7) y_num = 7;

        // 显示柱形图区域
        for (uint8_t i = 0; i <= RGB_LED_NUM_Y; i++)
        {
          if (i < y_num)
          {
            rgb.setRGB(x, i, column_rgb[single_color][0], column_rgb[single_color][1], column_rgb[single_color][2]);  // 点亮
          }
          else
          {
            rgb.setRGB(x, i, 0, 0, 0);    // 熄灭
          }
        }

        // 更新顶部像素
        rgb_top_update(x, y_num, 255, 255, 255);
      }
      break;

    default:
      break;
  }

  // 清屏
  if (vReal_max == 0)
  {
    if (++vReal_max0_cnt > 100)
    {
      for (uint8_t x = 0; x < RGB_LED_NUM_X; x++)
      {
        for (uint8_t y = 0; y <= RGB_LED_NUM_Y; y++)
        {
          rgb.setRGB(x, y, 0, 0, 0);
        }
      }
    }
  }
  else
  {
    vReal_max0_cnt = 0;
  }

  // 更新显示
  FastLED.show();

  #if 0

  for (uint16_t i = 0; i < SAMPLES/4; i++)
  {
    double abscissa;
    /* Print abscissa value */
    abscissa = ((i * 1.0 * samplingFrequency) / SAMPLES);
    Serial.print(abscissa, 6);
    Serial.print("Hz");
    Serial.print(" ");
    Serial.println(vReal[i], 4);
  }
  Serial.println();

  Serial.println(xHz, 6);

  #endif
}

/***********************************************************/
/* 顶部rgb更新                                             */
/* x:行 y:列                                               */
/***********************************************************/
void rgb_top_update(uint8_t x, uint8_t y, int r, int g, int b)
{
  static uint8_t  top[8] = {0};       // 当前顶部位置
  static uint16_t down_cnt[8] = {0};  // 下降时间计时

  // 限制硬件极限，最高只能到7
  if (y >= 7)
  {
    top[x] = 7;
    down_cnt[x] = 0;  // 重置计时
  }

  // 超过或等于当前顶部位置
  else if (y >= top[x])
  {
    top[x] = y;
    down_cnt[x] = 0;  // 重置计时
  }

  // 低于当前顶部位置
  else
  {
    down_cnt[x]++;

    // 还有下降空间且满足下降的时间
    if (top[x] > 0 && down_cnt[x] > 1)
    {
      top[x]--; // 下降一个像素
      down_cnt[x] = 0;
    }
  }

  rgb.setRGB(x, top[x], r, g, b);
}
